home *** CD-ROM | disk | FTP | other *** search
/ Underground / Underground CD1.iso / virii / zrodla / c / cache.asm < prev    next >
Encoding:
Assembly Source File  |  1998-01-14  |  15.1 KB  |  255 lines

  1. INTERRUPTS      SEGMENT AT 0H    ;This is where the disk interrupt
  2.  
  3.         ORG     13H*4            ;holds the address of its service routine
  4.  
  5. DISK_INT        LABEL   DWORD
  6.  
  7. INTERRUPTS      ENDS
  8.  
  9.  
  10.  
  11. CODE_SEG        SEGMENT
  12.  
  13.         ASSUME  CS:CODE_SEG
  14.  
  15.         ORG     100H            ;ORG = 100H to make this into a .COM file
  16.  
  17. FIRST:  JMP     LOAD_CACHE      ;First time through jump to initialize routine
  18.  
  19.  
  20.  
  21.         CPY_RGT DB      '(C)1985 S.Holzner'     ;A signature in bytes
  22.  
  23.         TBL_LEN DW      64 ;<-- # OF SECTORS TO STORE IN CACHE, MIN=24, MAX=124.
  24.  
  25.   ;THIS IS THE ONLY PLACE YOU MUST SET THIS NUMBER. EACH SECTOR = 512 BYTES.
  26.  
  27.         TIME    DW      0       ;Time used to time-stamp each sector
  28.  
  29.         OLD_CX  DW      0       ;Stores original value of CX (CX is used often)
  30.  
  31.         LOW_TIM DW      0       ;Used in searching for least recently used sect.
  32.  
  33.         INT13H  DD      0       ;Stores the original INT 13H address
  34.  
  35.         RET_ADR LABEL   DWORD   ;Playing games with the stack here to preserve
  36.  
  37.         RET_ADR_WORD    DW      2 DUP(0)            ;flags returned by Int 13H
  38.  
  39.  
  40.  
  41. DISK_CACHE      PROC    FAR     ;The Disk interrupt will now come here.
  42.  
  43.         ASSUME  CS:CODE_SEG
  44.  
  45.         CMP     AX,201H         ;Is this a read (AH=2) of 1 sector (AL=1)?
  46.  
  47.         JE      READ            ;Yes, jump to Read
  48.  
  49.         CMP     AH,3            ;No. Perchance a write or format?
  50.  
  51.         JB      OLD_INT         ;No, release control to old disk Int.
  52.  
  53.         JMP     WRITE           ;Yes, jump to Write
  54.  
  55. OLD_INT:PUSHF                   ;Pushf for Int 13H's final Iret
  56.  
  57.         CALL    INT13H          ;Call the Disk Int
  58.  
  59.         JMP     PAST            ;And jump past all usual Pops
  60.  
  61. READ:   PUSH    BX              ;Push just about every register ever heard of
  62.  
  63.         PUSH    CX
  64.  
  65.         PUSH    DX
  66.  
  67.         PUSH    DI
  68.  
  69.         PUSH    SI
  70.  
  71.         PUSH    DS
  72.  
  73.         PUSH    ES
  74.  
  75.         MOV     DI,BX       ;Int 13H gets data address as ES:BX, switch to ES:DI
  76.  
  77.         ASSUME  DS:CODE_SEG     ;Make sure all labels found correctly
  78.  
  79.         PUSH    CS              ;Move CS into DS by pushing CS, popping DS
  80.  
  81.         POP     DS
  82.  
  83.         MOV     OLD_CX,CX       ;Save original CX since we're about to use it
  84.  
  85.         CMP     DH,0            ;DH holds requested head -- head 0?
  86.  
  87.         JNE     NOT_FAT1        ;Nope, this can't be the first Fat sector
  88.  
  89.         CMP     CX,6            ;If this is the directory, check if we have a
  90.  
  91.         JE      FAT1            ; new disk.
  92.  
  93.         CMP     CX,2            ;Track 0 (CH)? Sector 2 (CL)?
  94.  
  95.         JNE     NOT_FAT1        ;If not, this sure isn't the FAT1
  96.  
  97. FAT1:   CALL    FIND_MATCH  ;DOS reads in this sector first to check disk format
  98.  
  99.         JCXZ    NONE            ;We'll use it for a check-sum. Do we have it
  100.  
  101.         MOV     BX,DI           ; stored yet? CX=0-->no. If yes, restore BX
  102.  
  103.         MOV     CX,OLD_CX       ; and CX from original values
  104.  
  105.         PUSHF                   ;And now do the Pushf and call of Int13H to read
  106.  
  107.         CALL    INT13H          ; FAT1
  108.  
  109.         JC      ERR             ;If error, leave
  110.  
  111.         MOV     CX,256          ;No error, FAT1 was read, check our value
  112.  
  113. REPE    CMPSW                   ; with CMPSW -- if no match, disk was changed
  114.  
  115.         JCXZ    BYE             ;Everything checks out, Bingo, exit.
  116.  
  117.         LEA     SI,TABLE        ;New Disk! Zero all the old disk's sectors
  118.  
  119.         MOV     CX,TBL_LEN      ;Loop over all entries, DL holds drive #
  120.  
  121. CLR:    CMP     DS:[SI+2],DL    ;Is this stored sector from the old disk?
  122.  
  123.         JNE     NO_CLR          ;Nope, don't clear this entry
  124.  
  125.         MOV     WORD PTR DS:[SI],0      ;Match, zero this entry, zero first word
  126.  
  127. NO_CLR: ADD     SI,518      ;Move on to next stored sector (512 bytes of stored
  128.  
  129.         LOOP    CLR         ; sector and 3 words of identification & time-stamp)
  130.  
  131.         JMP     BYE             ;Reset for new disk, let's leave
  132.  
  133. NONE:   CALL    STORE_SECTOR    ;Store FAT1 if there was no match to it
  134.  
  135.         JC      ERR             ;Error -- exit ungraciously
  136.  
  137.         JMP     BYE             ;No Error, Bye.
  138.  
  139. NOT_FAT1:                       ;The requested sector was not FAT1. Let's
  140.  
  141.         CALL    FIND_MATCH      ;get it. Or do we have it already?
  142.  
  143.         JCXZ    NO_MATCH        ;No, jump to No_Match, store sector
  144.  
  145.         MOV     CX,512          ;ES:DI and DS:SI already set up from Find_Match
  146.  
  147. REP     MOVSB                   ;Move 512 bytes to requested memory area
  148.  
  149.         CMP     WORD PTR [BX+4],0FFFFH          ;Is this a a directory sector?
  150.  
  151.         JE      BYE             ;Yes, don't reset time (already highest poss.)
  152.  
  153.         INC     TIME            ;No, reset the time, this sector just accessed
  154.  
  155.         MOV     AX,TIME         ;Move time into Time word of sector's 3 words
  156.  
  157.         MOV     [BX+4],AX       ; of identification
  158.  
  159.         JMP     BYE             ;And leave. If there's an article you'd like to
  160.  
  161. NO_MATCH:                       ;see, by all means write in C/O PC Magazine.
  162.  
  163.         CALL    STORE_SECTOR    ;Don't have this sector yet, get it.
  164.  
  165.         JC      ERR             ;If read failed, exit with error
  166.  
  167. BYE:    CLC                     ;The exit point. Clear carry flag, set AX=1
  168.  
  169.         MOV     AX,1            ; CY=0 --> no error, AH=0 --> error code = 0
  170.  
  171. ERR:    POP     ES              ;If error, preserve flags and AX with error code
  172.  
  173.         POP     DS              ;Pop all conceivable registers (except AX)
  174.  
  175.         POP     SI
  176.  
  177.         POP     DI
  178.  
  179.         POP     DX
  180.  
  181.         POP     CX              ;Now that the flags are set, we want to get the
  182.  
  183.         POP     BX              ;old flags off the stack (put there by original
  184.  
  185. PAST:   POP     CS:RET_ADR_WORD ;Int call) To do that we save the return address
  186.  
  187.         POP     CS:RET_ADR_WORD[2]      ;first and then pop the flags harmlessly
  188.  
  189.         POP     CS:OLD_CX       ;into Old_CX, and then jump to RET_ADR.
  190.  
  191.         JMP     CS:RET_ADR      ;Done with read. Now let's consider write.
  192.  
  193. WRITE:  PUSH    BX              ;Push all registers, past and present
  194.  
  195.         PUSH    CX
  196.  
  197.         PUSH    DX
  198.  
  199.         PUSH    DI
  200.  
  201.         PUSH    SI
  202.  
  203.         PUSH    DS
  204.  
  205.         PUSH    ES
  206.  
  207.         PUSH    AX
  208.  
  209.         CMP     AX,301H         ;Is this a write of one sector?
  210.  
  211.         JNE     NOSAVE          ;No, don't save it in the sector bank
  212.  
  213.         PUSH    CS              ;Yep, set DS (for call to Int13H label) and
  214.  
  215.         POP     DS              ; write this sector out
  216.  
  217.         PUSHF
  218.  
  219.         CALL    INT13H
  220.  
  221.         JNC     SAVE       ;If there was an error we don't want to save sector
  222.  
  223.         POP     CS:OLD_CX       ;Save AH error code, Pop old AX into Old_CX
  224.  
  225.         JMP     ERR             ;And jump to an ignoble exit
  226.  
  227. SAVE:   MOV     OLD_CX,CX       ;We're going to save this sector.
  228.  
  229.         MOV     DI,BX           ;Set up DI for string move (to store written
  230.  
  231.         CALL    FIND_MATCH      ; sector. Do we have it in memory? (set SI)
  232.  
  233.         JCXZ    LEAVE           ;Nope, Leave (like above's Bye).
  234.  
  235.         XCHG    DI,SI           ;Exchange destination and source
  236.  
  237.         PUSH    ES              ;Set up DS:SI to point to where data written
  238.  
  239.         POP     DS              ; from. We'll then use a string move
  240.  
  241.         PUSH    CS              ;Set up ES so ES:DI points to sector bank
  242.  
  243.         POP     ES              ; SI was set by Find_Match, Xchg'd into DI
  244.  
  245.         MOV     CX,512          ;Get ready to move 512 bytes
  246.  
  247. REP     MOVSB                   ;Here we go
  248.  
  249. LEAVE:  POP     AX              ;Here is the leave
  250.  
  251.         JMP     BYE             ;Which only pops AX and then jumps to Bye
  252.  
  253. NOSAVE: PUSH    CS              ;More than 1 sector written, don't save but
  254.  
  255.         POP     DS              ; do zero stored sectors that will be written
  256.  
  257.         MOV     AH,0            ;Use AX as loop index (AL=# of sectors to write)
  258.  
  259. TOP:    PUSH    CX              ;Save CX since destroyed by Find_Match
  260.  
  261.         CALL    FIND_MATCH      ;Do we have this one?
  262.  
  263.         JCXZ    NOPE            ;Nope if CX = 0
  264.  
  265.         MOV     WORD PTR [BX],0 ;There is a match, zero this sector
  266.  
  267. NOPE:   POP     CX              ;Restore CX, the sector index
  268.  
  269.         INC     CL              ;Move on to next one
  270.  
  271.         DEC     AX              ;Decrement loop index
  272.  
  273.         JNZ     TOP             ;And, unless that gives 0, go back again
  274.  
  275. POPS:   POP     AX              ;Pop 'em all, starting with AX
  276.  
  277.         POP     ES
  278.  
  279.         POP     DS
  280.  
  281.         POP     SI
  282.  
  283.         POP     DI
  284.  
  285.         POP     DX
  286.  
  287.         POP     CX
  288.  
  289.         POP     BX
  290.  
  291.         JMP     OLD_INT         ;And go back to OLD_INT for write.
  292.  
  293. DISK_CACHE      ENDP
  294.  
  295.  
  296.  
  297. FIND_MATCH      PROC    NEAR    ;This routine finds a sector in the sector bank
  298.  
  299.         PUSH    AX              ;And returns SI set to sector's entry, BX set
  300.  
  301.         LEA     SI,SECTORS      ; to the beginning of the 'table' -- the 3 words
  302.  
  303.         LEA     BX,TABLE        ;that precede all sectors. If there was no match
  304.  
  305.         MOV     AX,TBL_LEN      ; CX=0. When Int13H called, CH=trk #, CL=sec. #
  306.  
  307.         XCHG    AX,CX           ; DH=head #, DL=Drive #. Get Tbl_Len into CX
  308.  
  309. FIND:   CMP     DS:[BX],AX      ;Compare stored sector's original AX to current
  310.  
  311.         JNE     NO              ;If not, not.
  312.  
  313.         CMP     DS:[BX+2],DX    ;If so, check DX of stored sector with current
  314.  
  315.         JE      GOT_IT          ;Yes, there is a match, leave
  316.  
  317. NO:     ADD     BX,518          ;Point to next Table entry
  318.  
  319.         ADD     SI,518          ;And next sector too
  320.  
  321.         LOOP    FIND            ;Keep looping until there is a match
  322.  
  323. GOT_IT: POP     AX              ;If there is no match, CX will be left 0
  324.  
  325.         RET                     ;Return
  326.  
  327. FIND_MATCH      ENDP
  328.  
  329.  
  330.  
  331. STORE_SECTOR    PROC    NEAR    ;This routine, as it says, stores sectors
  332.  
  333.         MOV     BX,DI           ;Original BX (ES:BX was original data address)
  334.  
  335.         MOV     CX,OLD_CX       ; and CX restored (CX=trk#, Sector#)
  336.  
  337.         PUSHF                   ;Pushf for Int 13H's Iret and call it
  338.  
  339.         CALL    INT13H
  340.  
  341.         JNC     ALL_OK          ;If there was an exit, exit ignominiously
  342.  
  343.         JMP     FIN             ;If error, leave CY flag set, code in AH, exit
  344.  
  345. ALL_OK: PUSH    CX              ;No error, push used registers
  346.  
  347.         PUSH    BX              ; and find space for sector in sector bank
  348.  
  349.         PUSH    DX
  350.  
  351.         LEA     DI,SECTORS      ;Point to sector bank
  352.  
  353.         LEA     BX,TABLE        ; and Table
  354.  
  355.         MOV     CX,TBL_LEN      ; and get ready to loop over all of them to
  356.  
  357. CHK0:   CMP     WORD PTR DS:[BX],0      ;find if there is an unused sector
  358.  
  359.         JE      FOUND           ;If the first word is 0, use this sector
  360.  
  361.         ADD     DI,518          ;But this one isn't so update DI, SI and
  362.  
  363.         ADD     BX,518          ; loop again
  364.  
  365.         LOOP    CHK0
  366.  
  367.         MOV     LOW_TIM,0FFFEH  ;All sectors were filled, find least recently
  368.  
  369.         LEA     DI,SECTORS      ; used and write over that one
  370.  
  371.         LEA     SI,TABLE
  372.  
  373.         MOV     CX,TBL_LEN      ;Loop over all stored sectors
  374.  
  375. CHKTIM: MOV     DX,LOW_TIM      ;Compare stored sector to so-far low time
  376.  
  377.         CMP     [SI+4],DX
  378.  
  379.         JA      MORE_RECENT     ;If this one is more recent, don't use it
  380.  
  381.         MOV     AX,DI           ;This one is older than previous oldest
  382.  
  383.         MOV     BX,SI           ;Store sector bank address (DI) and table
  384.  
  385.         MOV     DX,[SI+4]       ; entry (now in SI)
  386.  
  387.         MOV     LOW_TIM,DX      ;And update the Low Time to this one
  388.  
  389. MORE_RECENT:
  390.  
  391.         ADD     DI,518          ;Move on to next stored sector
  392.  
  393.         ADD     SI,518          ;And next table entry
  394.  
  395.         LOOP    CHKTIM          ;Loop again until all covered
  396.  
  397.         MOV     DI,AX           ;Get Sector bank address of oldest into DI
  398.  
  399. FOUND:  POP     DX              ;Restore used registers
  400.  
  401.         POP     SI              ;Old BX (data read-to-address) --> SI
  402.  
  403.         POP     CX
  404.  
  405.         MOV     [BX],CX         ;Store the new CX as the sector's first word
  406.  
  407.         MOV     [BX+2],DX       ;2nd word of Table is sector's DX
  408.  
  409.         INC     TIME            ;Now find the new time
  410.  
  411.         MOV     AX,TIME         ;Prepare to move it into 3rd word of Table
  412.  
  413.         CMP     DH,0            ;Is this directory or FAT? (time-->FFFF)
  414.  
  415.         JNE     SIDE1           ;If head is not 0, check other head
  416.  
  417.         CMP     CX,9            ;Head zero, trk# 0, first sector? (directory)
  418.  
  419.         JLE     DIR             ;Yes, this is a piece we always want stored
  420.  
  421.         JMP     NOT_DIR         ;No, definitely not FAT or directory
  422.  
  423. SIDE1:  CMP     DH,1            ;Head 1?
  424.  
  425.         JNE     NOT_DIR         ;No, this is not File Alloc. Table or directory
  426.  
  427.         CMP     CX,2            ;Part of the top of the directory?
  428.  
  429.         JA      NOT_DIR         ;No, go to Not_Dir and set time
  430.  
  431. DIR:    MOV     AX,0FFFFH       ;Dir or FAT, set time high so always kept
  432.  
  433. NOT_DIR:MOV     [BX+4],AX       ;Not FAT or dir, store the incremented time
  434.  
  435.         PUSH    ES              ;And now get the data to fill the sector
  436.  
  437.         POP     DS              ;SI, DI already set. Now set ES and DS for
  438.  
  439.         PUSH    CS              ; string move.
  440.  
  441.         POP     ES
  442.  
  443.         MOV     CX,512          ;Move 512 bytes
  444.  
  445. REP     MOVSB                   ;Right here
  446.  
  447.         CLC                     ;Clear the carry flag (no error)
  448.  
  449. FIN:    RET                     ;Error exit here (do not reset CY flag)
  450.  
  451. STORE_SECTOR    ENDP
  452.  
  453. TABLE:  DW      3 DUP(0)        ;Table and sector storage begins right here
  454.  
  455. SECTORS:                        ;First thing to write over is the following
  456.  
  457.                                 ; booster program.
  458.  
  459. LOAD_CACHE        PROC    NEAR  ;This procedure intializes everything
  460.  
  461.         LEA     BX,CLEAR
  462.  
  463.         ASSUME  DS:INTERRUPTS   ;The data segment will be the Interrupt area
  464.  
  465.         MOV     AX,INTERRUPTS
  466.  
  467.         MOV     DS,AX
  468.  
  469.         MOV     AX,word ptr DISK_INT    ;Get the old interrupt service routine
  470.  
  471.         MOV     word ptr INT13H,AX      ; address and put it into our location         MOV     AX,word ptr DISK_INT[2]
  472.  
  473.                                         ; INT13H so we can call it.
  474.  
  475.         MOV     word ptr INT13H[2],AX
  476.  
  477.         MOV     word ptr DISK_INT,OFFSET DISK_CACHE  ;Now load address of Cache
  478.  
  479.         MOV     word ptr DISK_INT[2],CS   ;routine into the Disk interrupt
  480.  
  481.         MOV     AX,TBL_LEN              ;The number of sectors to store in cache
  482.  
  483.         MOV     CX,518                  ;Multiply by 518 (3 words of id and 512
  484.  
  485.         MUL     CX                      ; bytes of sector data)
  486.  
  487.         MOV     CX,AX                   ;Also, zero all the bytes so that
  488.  
  489. ZERO:   MOV     BYTE PTR CS:[BX],0      ; Store_Sector will find 1st word a 0,
  490.  
  491.         INC     BX                      ; indicating virgin territory.
  492.  
  493.         LOOP    ZERO
  494.  
  495.         MOV     DX,OFFSET TABLE         ;To attach in memory, add # bytes to
  496.  
  497.         ADD     DX,AX                   ;store to Table's location and use
  498.  
  499.         INT     27H                     ; Int 27H
  500.  
  501. LOAD_CACHE        ENDP
  502.  
  503. CLEAR:
  504.  
  505.         CODE_SEG        ENDS
  506.  
  507.         END     FIRST           ;END "FIRST" so 8088 will go to FIRST first.
  508.  
  509.